package com.atguigu.spzx.product.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson2.JSON;
import com.atguigu.spzx.common.annotation.GuiguCache;
import com.atguigu.spzx.model.dto.h5.ProductSkuDto;
import com.atguigu.spzx.model.dto.product.SkuSaleDto;
import com.atguigu.spzx.model.entity.product.Product;
import com.atguigu.spzx.model.entity.product.ProductDetails;
import com.atguigu.spzx.model.entity.product.ProductSku;
import com.atguigu.spzx.model.vo.h5.ProductItemVo;
import com.atguigu.spzx.common.constant.RedisConst;
import com.atguigu.spzx.product.mapper.ProductDetailsMapper;
import com.atguigu.spzx.product.mapper.ProductMapper;
import com.atguigu.spzx.product.mapper.ProductSkuMapper;
import com.atguigu.spzx.product.service.ProductService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service
@Transactional
@Slf4j
public class ProductServiceImpl implements ProductService {

    @Autowired
    ProductMapper productMapper;

    @Autowired
    ProductSkuMapper productSkuMapper;

    @Autowired
    ProductDetailsMapper productDetailsMapper;

    @Autowired
    RedisTemplate<String,String> redisTemplate;

    @Autowired
    RedissonClient redissonClient;

    @Override
    public PageInfo<ProductSku> findPage(Integer page, Integer limit, ProductSkuDto productSkuDto) {
        PageHelper.startPage(page,limit);
        List<ProductSku> list = productMapper.findPage(productSkuDto);  //  Page extends ArrayList
        return new PageInfo(list);
    }


    //目标方法：执行过程中需要进行切面处理
    @GuiguCache(
            cacheKey = RedisConst.SKUKEY_PREFIX + "#{#params[0]}" + RedisConst.SKUKEY_SUFFIX,
            enableLock = true ,
            lockName = RedisConst.PRODUCT_LOCK_SUFFIX+ "#{#params[0]}")
    @Override
    public ProductItemVo item(Long skuId) {
        return getItemVoFromDb(skuId);
    }





    /*@Override
    public ProductItemVo item(Long skuId) {
        ProductItemVo productItemVo = null;
        //***********************************************************************************

        //校验
        RBloomFilter<Object> bloomFilter = redissonClient.getBloomFilter(RedisConst.PRODUCT_BLOOM_FILTER);
        if(!bloomFilter.contains(skuId)){ //判断商品在布隆过滤器中是否存在？
            productItemVo = new ProductItemVo();
            log.info("from RBloomFilter data not exists 返回空对象= "+ productItemVo);
            return productItemVo;
        }

        //***********************************************************************************
        //1.先走缓存，缓存有直接返回。效率大大提高
        String productItemVoJson = redisTemplate.opsForValue().get(RedisConst.SKUKEY_PREFIX + skuId + RedisConst.SKUKEY_SUFFIX);
        if(StringUtils.hasText(productItemVoJson)){
            productItemVo = JSON.parseObject(productItemVoJson, ProductItemVo.class);
            log.info("from redis data ProductItemVo="+productItemVo);
            return productItemVo;
        }

        //解决缓存击穿问题，采用Redisson提供分布式锁机制来解决。
        String key = RedisConst.PRODUCT_LOCK_SUFFIX+skuId;
        RLock lock = redissonClient.getLock(key);
        boolean tryLock = lock.tryLock(); //  30秒自动释放锁   看门狗    过期时间/3       默认过期时间也可以修改。需要重置Config配置  org.redisson.config.Config.lockWatchdogTimeout
        if(tryLock){
            try {
                //2.缓存没有走数据库，将数据存放缓存一份。给下次请求利用缓存，提高效率
                productItemVo = getItemVoFromDb(skuId);
                if(productItemVo==null){
                    productItemVo = new ProductItemVo();
                    redisTemplate.opsForValue().set(RedisConst.SKUKEY_PREFIX + skuId + RedisConst.SKUKEY_EMPTY_TIMEOUT,JSON.toJSONString(productItemVo),
                            RedisConst.SKUKEY_TIMEOUT, TimeUnit.SECONDS);
                    log.info("from mysql data ProductItemVo="+productItemVo);
                }else{
                    redisTemplate.opsForValue().set(RedisConst.SKUKEY_PREFIX + skuId + RedisConst.SKUKEY_SUFFIX,JSON.toJSONString(productItemVo),
                            RedisConst.SKUKEY_TIMEOUT, TimeUnit.SECONDS);
                    log.info("from mysql data ProductItemVo="+productItemVo);
                }

            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                //释放锁
                lock.unlock();
            }
        }else {
            return item(skuId);
        }
        return productItemVo;
    }*/

    //@NotNull
    private ProductItemVo getItemVoFromDb(Long skuId) {
        try {
            //1.根据skuId查询ProductSku对象
            ProductSku productSku = productSkuMapper.getById(skuId);

            //2.查询商品对象
            Long productId = productSku.getProductId(); //ProductSku表的外键，它就是Product表的主键
            Product product = productMapper.getById(productId);

            //3.获取轮播图集合
            String sliderUrls = product.getSliderUrls(); //   url,url,url
            String[] sliderUrlsArray = sliderUrls.split(",");
            List<String> sliderUrlsList = Arrays.asList(sliderUrlsArray);

            //4.获取详情图集合
            ProductDetails productDetails =  productDetailsMapper.getByProductId(productId);
            String imageUrls = productDetails.getImageUrls(); // http://139.198.127.41:9000/spzx/20230525/665832167-5_u_1.jpg,http://139.198.127.41:9000/spzx/20230525/665832167-6_u_1.jpg,http://139.198.127.41:9000/spzx/20230525/665832167-4_u_1.jpg,http://139.198.127.41:9000/spzx/20230525/665832167-1_u_1.jpg,http://139.198.127.41:9000/spzx/20230525/665832167-5_u_1 (1).jpg,http://139.198.127.41:9000/spzx/20230525/665832167-3_u_1.jpg
            String[] imageUrlsArray = imageUrls.split(",");
            List<String> imageUrlsList = Arrays.asList(imageUrlsArray);


            //5.从Product表可以获取商品规格字符串 ——> 转换为JsonArray数组
            String specValueJsonStr = product.getSpecValue();//     '[{"key":"颜色","valueList":["白色","红色","黑色"]},{"key":"内存","valueList":["8G","18G"]}]'
            JSONArray specValueJsonArray = JSONObject.parseArray(specValueJsonStr);

            //6.根据ProductId查询ProductSku集合，获取商品规格对应商品skuId信息的Map<String,Long>数据
            Map<String,Object> skuSpecValueMap = new HashMap<>();
            List<ProductSku> productSkuList = productSkuMapper.getProductSkuListByProductId(productId);
            productSkuList.forEach(sku -> {
                skuSpecValueMap.put(sku.getSkuSpec(),sku.getId());
            });

            //封装
            ProductItemVo productItemVo = new ProductItemVo();
            productItemVo.setProductSku(productSku);
            productItemVo.setProduct(product);
            productItemVo.setSliderUrlList(sliderUrlsList);
            productItemVo.setDetailsImageUrlList(imageUrlsList);
            productItemVo.setSpecValueList(specValueJsonArray);
            productItemVo.setSkuSpecValueMap(skuSpecValueMap);

            //返回
            return productItemVo;
        } catch (Exception e) {
            return null;
        }
    }


    @Override
    public ProductSku getBySkuId(Long skuId) {
        return productSkuMapper.getById(skuId);
    }

    @Override
    public Boolean updateSkuSaleNum(List<SkuSaleDto> skuSaleDtoList) {
        if(!CollectionUtils.isEmpty(skuSaleDtoList)) {
            for(SkuSaleDto skuSaleDto : skuSaleDtoList) {
                productSkuMapper.updateSale(skuSaleDto.getSkuId(), skuSaleDto.getNum());
            }
        }
        return true;
    }
}
